package com.etymgiko.spaceshipshop.dao.hibernate;

import com.etymgiko.spaceshipshop.dao.SpaceShipDao;
import com.etymgiko.spaceshipshop.model.SpaceShip;
import com.etymgiko.spaceshipshop.Constants;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import java.sql.SQLException;
import java.util.List;

/**
 * Dao to work with Spaceship object implemented using Hibernate.
 *
 * @author Ivan Holub
 */
public class SpaceShipDaoHibernate extends HibernateDaoSupport implements SpaceShipDao {

    /**
     * Number of elements in page.
     */
    private static final int PAGE_SIZE = Constants.PAGE_SIZE;

    /**
     * {@inheritDoc} 
     */
    public SpaceShip getSpaceShip(Long id) {
        return (SpaceShip) getHibernateTemplate().get(SpaceShip.class, id);
    }

    /**
     * {@inheritDoc}
     */
    public void saveSpaceShip(SpaceShip spaceShip) {
        getHibernateTemplate().saveOrUpdate(spaceShip);
    }

    /**
     * {@inheritDoc}
     */
    public long findSpaceShipsCount(final Long userId, final String filter) {
        final String pattern = "%" + filter + "%";
        return (Long) getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                boolean isOwnerNull = userId == null;
                String sqlOwner;
                if (isOwnerNull) {
                    sqlOwner = "spaceShip.owner is null";
                } else {
                    sqlOwner = "spaceShip.owner.id = ?";
                }
                boolean isFilterNull = filter == null || "".equals(filter);
                String sqlFilter;
                if (isFilterNull) {
                    sqlFilter = "";
                } else {
                    sqlFilter = " and (spaceShip.name like ? or spaceShip.typename like ? or spaceShip.manufacturer like ?)";
                }
                Query query = session.createQuery("select count(spaceShip) from SpaceShip spaceShip where "
                        + sqlOwner + sqlFilter);
                int counter = 0;
                if (!isOwnerNull) {
                    query.setParameter(counter++, userId);
                }
                if (!isFilterNull) {
                    query.setParameter(counter++, pattern);
                    query.setParameter(counter++, pattern);
                    query.setParameter(counter, pattern);
                }
                return query.uniqueResult();
            }
        });
    }

    /**
     * {@inheritDoc}
     */
    public List<SpaceShip> findSpaceShips(final Long userId, final String filter, final int pageNumber) {
        final String pattern = "%" + filter + "%";
        @SuppressWarnings(value = "unchecked")
        List<SpaceShip> retValue = (List<SpaceShip>) getHibernateTemplate().executeFind(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                boolean isNull = userId == null;
                String sqlOwner;
                if (isNull) {
                    sqlOwner = "spaceShip.owner is null";
                } else {
                    sqlOwner = "spaceShip.owner.id = ?";
                }
                boolean isFilterNull = filter == null || "".equals(filter);
                String sqlFilter;
                if (isFilterNull) {
                    sqlFilter = "";
                } else {
                    sqlFilter = " and (spaceShip.name like ? or spaceShip.typename like ? or spaceShip.manufacturer like ?)";
                }
                Query query = session.createQuery("from SpaceShip spaceShip where "
                    + sqlOwner + sqlFilter);
                int counter = 0;
                if (!isNull) {
                    query.setParameter(counter++, userId);
                }
                if (!isFilterNull) {
                    query.setParameter(counter++, pattern);
                    query.setParameter(counter++, pattern);
                    query.setParameter(counter, pattern);
                }
                query.setFirstResult((pageNumber - 1) * PAGE_SIZE);
                query.setMaxResults(PAGE_SIZE);
                return query.list();
            }
        });
        return retValue;
    }

}
